﻿using Cysharp.Threading.Tasks;
using Net;
using Net.Server;
using Net.Share;
using System.Collections.Concurrent;
using Wordgames;
using WordGames.Service;
using WordGames.System;

namespace WordGames
{
    public class GameService : TcpServer<GamePeer>
    {
        public ConcurrentDictionary<long, Player> Players { get; private set; } = new();

        protected override void OnStartupCompleted()
        {
            base.OnStartupCompleted();
            OnNetworkDataTraffic += (df) =>
            {
                Console.Title = $"Game {Port} {df}";
            };
        }

        protected override void OnRpcExecute(GamePeer client, IRpcModel model)
        {
            _ = OnMessageHandler(client, model);
        }

        public async override UniTask OnMessageHandler(ClientUnitBase self, IRpcModel model)
        {
            switch ((ProtoType)model.Protocol)
            {
                case ProtoType.PlayerEnterGame:
                    {
                        var client = self as GamePeer;
                        var token = client.Token;
                        var userId = model.AsLong;
                        var remoteId = model.AsLong;
                        var account = model.AsString;
                        var gateRoute = model.AsString;
                        if (Players.TryGetValue(userId, out var player))
                        {
                            var cluster = ClusterSystem.GetCluster<GateService>(this);
                            var gateClient = await cluster.GetConnect(player.GateRoute);
                            gateClient.Call(ProtoType.SignOut_GameToGate, player.RemoteId, player.UserData.Name);
                        }
                        else player = new Player();
                        player.UserId = userId;
                        player.RemoteId = remoteId;
                        player.GateRoute = gateRoute;
                        Players.TryAdd(userId, player);
                        player.UserData = await ClusterSystem.DBCluster.QueryAsync<UserData>(account, $"account = '{account}'");
                        client.Response(ProtoType.PlayerEnterGame, token, 1);
                    }
                    break;
                case ProtoType.SetPlayerName:
                    {
                        var client = self as GamePeer;
                        var userId = model.AsLong;
                        var name = model.AsString;
                        if (Players.TryGetValue(userId, out var player))
                        {
                            player.UserData.Name = name;
                            client.Response(ProtoType.SetPlayerName, 1);
                        }
                    }
                    break;
                case ProtoType.PlayerExitGame:
                    {
                        var userId = model.AsLong;
                        if (Players.TryRemove(userId, out var player))
                        {
                        }
                    }
                    break;
                case ProtoType.WorldChat:
                    {
                        var userId = model.AsLong;
                        var message = model.AsString;
                        var name = "";
                        if (Players.TryGetValue(userId, out var player))
                        {
                            name = player.UserData.Name;
                        }
                        var cluster = ClusterSystem.GetCluster<GameService>(this);
                        cluster.Multicast(ProtoType.WorldChat_GameToGame, name, message);
                    }
                    break;
                case ProtoType.WorldChat_GameToGame:
                    {
                        var name = model.AsString;
                        var message = model.AsString;
                        foreach (var player in Players.Values)
                        {
                            var cluster = ClusterSystem.GetCluster<GateService>(this);
                            cluster.Multicast(ProtoType.WorldChat_GameToGate, player.RemoteId, name, message);
                        }
                    }
                    break;
            }
        }
    }
}